using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace MapEditor
{
    public class GraphicsEngine
    {

# region properties and variables
        public Bitmap Buffer;

        //offsets of the map we're drawing on the screen
        public int XOffset = 0;
        public int YOffset = 0;

        private GameGraphics GameGraphics;

        public int ImageWidth;
        public int ImageHeight;

        private Graphics g;
        private Graphics myGraphics;

        private Rectangle picRect;
        private Rectangle cropRect;


        private Bitmap _CroppedMapBuffer;
        public Bitmap CroppedMapBuffer
        {
            get { return _CroppedMapBuffer; }
            set { _CroppedMapBuffer = value;}

        }

        private Map _Map;
        public Map Map
        {
            get
            {
                return _Map;
            }
            set
            {
                _Map=value;
                g = Graphics.FromImage(value.BaseImage);

            }

        }


#endregion


#region constructor
           public GraphicsEngine()
            //constructor
        {
            //initialise the Game Graphics (icons, etc.)
            GameGraphics = new GameGraphics();
        }
     
#endregion


#region map drawing methods
        public bool CreateBuffers()
            //creates the graphic buffers for drawing to the screen
        {
            Buffer = new Bitmap(ImageWidth, ImageHeight);
            CroppedMapBuffer = new Bitmap(ImageWidth, ImageHeight);
            myGraphics = Graphics.FromImage(Buffer);
            UpdateMap(0, 0);
            return true;
        }

        public bool CreateBaseMap()
            //copies the current cropped map to the drawing buffer
        {
            Buffer = (Bitmap)CroppedMapBuffer.Clone();

            return true;
        }

        public bool UpdateMap(int scrollX, int scrollY)
        //this is only called if we have to draw a new section of screen - saves 30-45ms!
        {
            if (((scrollX < 0) && (scrollY < 0)) || ((scrollX > ImageWidth) && (scrollY > ImageHeight)))
            {
                return false;
            }

            if (scrollX < 0) { scrollX = 0; }
            if (scrollY < 0) { scrollY = 0; }
            if (scrollX > Map.Width-ImageWidth) { scrollX = Map.Width-ImageWidth; }
            if (scrollY > Map.Height-ImageHeight) { scrollY = Map.Height-ImageHeight; }

            XOffset = scrollX;
            YOffset = scrollY;




            //we should only do this if we have moved more than 10 pix
            Timer timer = new Timer();
            timer.StartTimer();

            DrawUpdatedMap();
            timer.StopTimer();

            timer.StartTimer();
            DrawRoofs();
            timer.StopTimer();
            return true;
        }

        private bool DrawUpdatedMap()
        {
            //we do this if the scrollbars have been activated, and it updates the main cropped map bitmap
            //get a new buffer
            g = Graphics.FromImage(CroppedMapBuffer);

            //paint the current map offset to the buffer
            picRect = new Rectangle(0, 0, ImageWidth, ImageHeight);
            cropRect = new Rectangle(XOffset, YOffset, ImageWidth, ImageHeight);
            Bitmap xx = Map.BaseMap.Clone(cropRect,Map.BaseMap.PixelFormat);

            g.DrawImage(xx,0,0);
            //g.DrawImage(Map.BaseImage, picRect, cropRect, GraphicsUnit.Pixel);
            return true;
        }

        private bool DrawRoofs()
        {
            

            int roofsdrawn = 0;
            bool DrawRoof = false;
            myGraphics = Graphics.FromImage(Buffer);

            for (int looper = 0; looper < Map.Roofs.RoofArray.Length; looper++)
            {
                //draw the roof exteriors
                for (int looper2 = 0; looper2 < 12; looper2++)
                {
                    if (Map.Roofs.RoofArray[looper].Vertices[looper2] != null)
                    {
                        if (OnScreen(Map.Roofs.RoofArray[looper].Vertices[looper2].XCoordinate, Map.Roofs.RoofArray[looper].Vertices[looper2].YCoordinate))
                        {
                            DrawRoof = true;
                            break;
                        }
                        else
                        {
                            DrawRoof = false;
                        }

                    }
                }
                if (DrawRoof)
                {
                    roofsdrawn++;
                    DrawExterior(looper);
                }

            }

            Console.Write("drew: " + roofsdrawn + " roofs");
            return true;
        }

        public Image GetScreen()
        // Returns an image showing the current map cropped and offset, with all elements drawn on it
        {
            //myGraphics = null;
            return Buffer;
        }


#endregion


#region soldier drawing routines
        private bool OnScreen(int X, int Y)
        //is the thing on screen? we only draw these!
        {
            bool returnValue = false;

            if ((X > XOffset) && X < (XOffset + ImageWidth))
            {
                if ((Y > YOffset) && Y < (YOffset + ImageHeight))
                {
                    returnValue = true;
                }
            }
            return returnValue;

        }

        public bool DrawSoldiers(Company[] Companies)
        //draws all soldiers on the map
        {
            myGraphics = Graphics.FromImage(Buffer);
            
            //go through all companies
            for (int companyLooper=0;companyLooper<Companies.Length;companyLooper++)
            {
                //then go through all the squads
                for (int squadLooper = 0; squadLooper < Companies[companyLooper].Squads.Length; squadLooper++)
                {
                   //then go through all the soldiers
                    for (int looper = 0; looper < Companies[companyLooper].Squads[squadLooper].Soldiers.Length; looper++)
                    {
                        //if the soldier is in a building then draw the interior
                        int roofID = Map.InsideBuilding(Companies[companyLooper].Squads[squadLooper].Soldiers[looper].X, Companies[companyLooper].Squads[squadLooper].Soldiers[looper].Y);
                        if (roofID != -1)
                        {
                            DrawInterior(roofID);
                        }
                        //only draw the soldier if it's on the screen!
                        bool selected = false;
                        if (Companies[companyLooper].CurrentlySelectedSquad == squadLooper)
                        {
                            selected = true;
                            //draw the target pip
                            if (OnScreen(Companies[companyLooper].Squads[squadLooper].Order.OrderPosition.X, Companies[companyLooper].Squads[squadLooper].Order.OrderPosition.Y))
                            {
                                DrawOrderTarget(Companies[companyLooper].Squads[squadLooper], Companies[companyLooper].Squads[squadLooper].Order.CurrentOrder);
                            }

                        }
                        DrawSoldier(Companies[companyLooper].Squads[squadLooper], looper,selected);
                    }

                }
            }

            for (int looper = 0; looper < Map.Roofs.NumberOfRoofs; looper++)
            {
                Map.Roofs.RoofArray[looper].ShowInterior = false;
            }

            return true;
        }

        private void DrawSoldier(Squad Squad, int currentSoldier, bool selected)
        {
            if (OnScreen(Squad.Soldiers[currentSoldier].X, Squad.Soldiers[currentSoldier].Y))
            {
                Soldier mySoldier = Squad.Soldiers[currentSoldier];
                int xTransform = mySoldier.X - mySoldier.SoldierImage.Center.X - XOffset;
                int yTransform = mySoldier.Y - mySoldier.SoldierImage.Center.Y - YOffset;
                int angle = mySoldier.Facing;

                Rectangle rect = new Rectangle(-1 * (mySoldier.SoldierImage.Center.X), -1 * (mySoldier.SoldierImage.Center.Y), mySoldier.SoldierImage.Width, mySoldier.SoldierImage.Height);
                Rectangle offrect = new Rectangle(xTransform, yTransform, mySoldier.SoldierImage.Width, mySoldier.SoldierImage.Height);

                myGraphics.TranslateTransform(xTransform, yTransform);
                myGraphics.RotateTransform(angle);
                myGraphics.DrawImage(mySoldier.SoldierImage.Draw(), rect);
                myGraphics.ResetTransform();

                //if the squad is selected, and we are on the leader (soldier 0 for the moment)
                //draw the selected tag        
                if ((selected))
                {
                    //draw selected pip
                    if (currentSoldier == Squad.SquadLeader)
                    {
                        DrawSelectedPip(xTransform, yTransform);
                    }
                    else
                    {
                        DrawSoldierSelectedPip(xTransform, yTransform);
                    }


                }

                mySoldier = null;

            }
        }

        private void DrawSelectedPip(int xTransform, int yTransform)
            //draw the squad leader selected pip
        {
            myGraphics.DrawImage(GameGraphics.SelectedSquadLeader, new Rectangle(xTransform - (GameGraphics.SelectedSquadLeader.Width / 2), yTransform - (GameGraphics.SelectedSquadLeader.Height / 2), GameGraphics.SelectedSquadLeader.Width, GameGraphics.SelectedSquadLeader.Height));
        }

        private void DrawSoldierSelectedPip(int xTransform, int yTransform)
            //draw the soldier selected pip
        {
            myGraphics.DrawImage(GameGraphics.SelectedSoldier, new Rectangle(xTransform - (GameGraphics.SelectedSoldier.Width / 2), yTransform - (GameGraphics.SelectedSoldier.Height / 2), GameGraphics.SelectedSoldier.Width, GameGraphics.SelectedSoldier.Height));
        }

        private void DrawOrderTarget(Squad Squad, Order.OrderType CurrentOrder)
            //draw the order pip
        {
            switch (CurrentOrder)
            {
                case Order.OrderType.Move:
                    myGraphics.DrawImage(GameGraphics.MoveTarget, new Rectangle(Squad.Order.OrderPosition.X - XOffset - (GameGraphics.MoveTarget.Width / 2), Squad.Order.OrderPosition.Y - YOffset - (GameGraphics.MoveTarget.Height / 2), GameGraphics.MoveTarget.Width, GameGraphics.MoveTarget.Height));
                    break;
            }
        }
#endregion



#region roof drawing routines
        public bool DrawInterior(int RoofID)
        //draw the roof interior
        {
            if (!Map.Roofs.RoofArray[RoofID].ShowInterior)
            {

                myGraphics.DrawImage(Map.Roofs.RoofArray[RoofID].InteriorImage, Map.Roofs.RoofArray[RoofID].RoofPosition.XCoordinate - XOffset, Map.Roofs.RoofArray[RoofID].RoofPosition.YCoordinate - YOffset);
                Map.Roofs.RoofArray[RoofID].ShowInterior = true;
            }
            return true;


        }

        public bool DrawExterior(int RoofID)
        //draw the roof interior
        {
            myGraphics.DrawImage(Map.Roofs.RoofArray[RoofID].ExteriorImage, Map.Roofs.RoofArray[RoofID].RoofPosition.XCoordinate - XOffset, Map.Roofs.RoofArray[RoofID].RoofPosition.YCoordinate - YOffset);
            return true;
        }
#endregion


#region line drawing code
        public bool DrawLine(Point Origin, Point Destination)
        {
            System.Drawing.Pen myPen;
            myPen = new System.Drawing.Pen(System.Drawing.Color.Blue);
            myPen.Width = 4.0F;

            myGraphics = Graphics.FromImage(Buffer);
            myGraphics.DrawLine(myPen, Origin.X , Origin.Y, Destination.X, Destination.Y);
            //myGraphics.DrawEllipse(myPen, Destination.X-10, Destination.Y-10, 20, 20);

            String drawString = CC.GetMetres((int)(MathUtils.GetDistance(Origin,Destination))).ToString() + "m";
             
            // Create font and brush.
            Font drawFont = new Font("Arial", 8,FontStyle.Bold);
            SolidBrush drawBrush = new SolidBrush(Color.White);
                     
            // Create point for upper-left corner of drawing.
            PointF drawPoint = new PointF(Destination.X+10, Destination.Y+10);

            myGraphics.DrawString(drawString, drawFont, drawBrush, drawPoint);

            myPen.Dispose();

            return true;
            //formGraphics.Dispose();
        }



#endregion




    }
}
